#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <asm/uaccess.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include<linux/sched.h>
#include <linux/slab.h>

#define MESSAGE_LENGTH 1024
static char Message[MESSAGE_LENGTH] = {0};/*наш буфер*/
static int pos;/*позиция с которой продолжится чтение,
если буфер принимающего полон, а в нашем еще что-либо есть*/
static int globlen;/*количество записанных байт пишущим*/

static DECLARE_WAIT_QUEUE_HEAD(WaitQ);/*очередь с помощью которой
синхронизируем процессы*/

char flag;/*флаг, который проверяется при синхронизации процессов*/

static int myopen_read(struct inode *inode, struct  file *file)
{
	return 0;
}

static int myopen_write(struct inode *inode, struct  file *file)
{
	return 0;
}

static int myread(struct file *filp, char *buffer,
size_t length, loff_t *offset)
{
	int i;/*счетчик по позиции  в нашем буфере*/
	int j = 0;/*счетчик по позиции в буфере читающего*/
	int res = 1;/*переменная, которая возвращает значение 0
если 60 секнд прошли*/
	/*printk(KERN_INFO "read work\n");*/
	if (flag == 0)
		res = wait_event_interruptible_timeout(WaitQ, flag != 0, 6000);
/*выполнение синхронизации*/
	if (res <= 0)
		return res;
	for (i = pos; length && (i < globlen); i++) {
		put_user(Message[i], buffer+j);
		j++;
		length--;
	} /*чтение в буфер читающего, соотвествующие операции со счетчиками*/
	/*printk(KERN_INFO "read len %d j %d i %d  mes %d\n",
length, j, i, Message[i]);*/
	if (i < globlen)
		pos = i;/*ситуация, если буфер читающего полон, а в нашем
осталось что-либо*/
	else {
		pos = 0;/*ситуация, когда наш буфер считан полность*/
		memset(Message, 0, 1024);/*обнуляем его, счетчики и флаг*/
		flag = 0;
		wake_up(&WaitQ);/*пробуждаем пишущий процес
для заполнения буфера*/
	}
	return i;/*возвращаем количество отданных данных*/
}


static int mywrite(struct file *filp,
const char *buff, size_t len, loff_t * off)
{
	int res = 1;/*возвращается с отрицательным значением при
неудачной синхронизации*/
	int i;/*счетчик цикла*/
	/*printk(" write work\n");*/
	if (flag != 0)
		res = wait_event_interruptible(WaitQ, flag == 0);
/*выполняется синхронизация, ожидаем сигнал от читательского процесса,
чтоб проверить флаг*/
	if (res < 0)
		return res;
	for (i = 0; i < MESSAGE_LENGTH - 1 && i < len; i++)
		get_user(Message[i], buff + i);/*копируем данные из
буфера пишушего в наш*/
	/*Message[i] = '\0';*/
	flag = 1;/*выставляем флаги глобальную переменную в
нужное значение*/
	/*printk("write len %d i %d \n",len,i);*/
	globlen = i;
	wake_up(&WaitQ);/*пробуждаем читательский процесс*/
	return i;/*возвращаем количество полученных данных*/
}


static struct file_operations myhandlers_read = {
	.owner = THIS_MODULE,
	.read = myread,
	.open = myopen_read,
	/*.write=seq_write,*/
};

static struct file_operations myhandlers_write = {
	.owner = THIS_MODULE,
	.write = mywrite,
	.open = myopen_write,
	/*.read=seq_read,*/
};


int init_module()
{
	globlen = 0;/*присваиваем переменным нулевые значения*/
	pos = 0;
	flag = 0;
	proc_create("read", 0, NULL, &myhandlers_read);/*создаем файлы*/
	proc_create("write", 0, NULL, &myhandlers_write);
	return 0;
}


void cleanup_module()
{
	remove_proc_entry("read", 0);/*удаляем файлы*/
	remove_proc_entry("write", 0);
}
